home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 January: Mac OS SDK / Dev.CD Jan 96 SDK / Dev.CD Jan 96 SDK1.toast / Development Kits (Disc 1) / AOCE / Development Tools / Sample Code / Digital Signatures / Digital Signature Demo / Source ƒ / DemoEditDoc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-11  |  10.8 KB  |  457 lines  |  [TEXT/KAHL]

  1. /*
  2.  * DemoEditDoc.c
  3.  * Copyright © 1993 Apple Computer Inc. All rights reserved.
  4.  * Portions of this file are revised from CEditDoc.c:
  5.  * Copyright © 1989 Symantec Corporation. All rights reserved.
  6.  * Used by permission.
  7.  *
  8.  * DemoEditDoc is a sub-class to the Think C "TinyEdit"
  9.  * CEditDoc that adds several Digital Signature related
  10.  * commands:
  11.  *        cmdOpenSignedFile verifies the signature of an existing,
  12.  *            signed, file and opens it, read-only, if successful.
  13.  *            Note that, when a file is signed, the Digital
  14.  *            Signature Manager marks it "read-only"
  15.  *
  16.  *        cmdCloseAndSignFile    closes a file (after it was written)
  17.  *            and signs it.
  18.  */
  19. #include <CApplication.h>
  20. #include <CBartender.h>
  21. #include <CDataFile.h>
  22. #include <CError.h>
  23. #include <TBUtilities.h>
  24. #include <CWindow.h>
  25. #include "DemoEditDoc.h"
  26. #include "CSignedDataFile.h"
  27. #include <OCEErrors.h>
  28. #include "Demo.h"
  29.  
  30. extern OSType                gSignature;
  31. extern CApplication            *gApplication;
  32. extern Boolean                gHasDigitalSignatureManager;
  33.  
  34. void                Message(
  35.         const StringPtr            textString
  36.     );
  37. void                        ErrorMessage(
  38.         OSErr                    macErr,
  39.         const StringPtr            textString
  40.     );
  41.  
  42. extern    CBartender    *gBartender;    /* The menu handling object */
  43. extern    CError        *gError;        /* The error handling object */
  44.  
  45. /*
  46.  * IDemoEditDoc
  47.  * Just do the standard initialization.
  48.  */
  49. void
  50. DemoEditDoc::IDemoEditDoc(
  51.         CApplication                *aSupervisor,
  52.         Boolean                        printable
  53.     )
  54. {
  55.         inherited::IEditDoc(aSupervisor, printable);
  56. }
  57.  
  58. /*
  59.  * DoCommand
  60.  * Recognize the "Save, Close, and Sign" menu option.
  61.  */
  62. void
  63. DemoEditDoc::DoCommand(
  64.         long                        theCommand
  65.     )
  66. {
  67.         switch (theCommand) {
  68.         case cmdCloseAndSignFile:
  69.             this->CloseAndSignFile();
  70.             break;
  71.         default:
  72.             inherited::DoCommand(theCommand);
  73.             break;
  74.         }
  75. }
  76.  
  77. /*
  78.  * Activate
  79.  * Override this to enable the Close and Sign document
  80.  * method when the window becomes active.
  81.  */
  82. void
  83. DemoEditDoc::Activate(void)
  84. {
  85.         inherited::Activate();
  86.         if (gHasDigitalSignatureManager)
  87.             gBartender->EnableCmd(cmdCloseAndSignFile);
  88. }
  89.  
  90. /*
  91.  * UpdateMenus
  92.  * If this is called, we know that there is a document.
  93.  * If the Digital Signature Manager is available, enable
  94.  * the "Save, Close, and Sign" menu option (it is disabled
  95.  * by default).
  96.  */
  97. void
  98. DemoEditDoc::UpdateMenus(void)
  99. {
  100.         inherited::UpdateMenus();
  101.         if (gHasDigitalSignatureManager)
  102.             gBartender->EnableCmd(cmdCloseAndSignFile);
  103. }
  104.  
  105. /*
  106.  * DoSaveAs
  107.  * This subclass to CEditDoc::DoSaveAs only exists
  108.  * to create files with TeachText as their creator.
  109.  * Note, also, that we notice the dupFNErr: you can
  110.  * get this error if you try to Save As on top of
  111.  * a locked file (Sign File creates locked files.)
  112.  */
  113. Boolean
  114. DemoEditDoc::DoSaveAs(
  115.         SFReply                    *macSFReply
  116.     )
  117. {
  118.         Boolean                result;
  119.         OSType                oldSignature;
  120.         
  121.         oldSignature = gSignature;
  122.         gSignature = 'ttxt';        /* TeachText    */
  123.         TRY {
  124.             result = inherited::DoSaveAs(macSFReply);
  125.         }
  126.         CATCH {
  127.             gSignature = oldSignature;
  128.             if (gLastError == dupFNErr) {
  129.                 /*
  130.                  * This error appears if you try
  131.                  * to Save over a read-only file,
  132.                  * selecting "Replace" in the
  133.                  * "Replace existing file" dialog.
  134.                  */
  135.                 Message(
  136.                     "\pDuplicate file name error:"
  137.                     " please choose a different name."
  138.                     " (You cannot replace a read-only file.)"
  139.                 );
  140.                 gApplication->JumpToEventLoop();
  141.             }
  142.         }
  143.         ENDTRY;
  144.         gSignature = oldSignature;
  145.         return (result);
  146. }
  147.  
  148. /*
  149.  * OpenAndVerifyFile
  150.  * Check for a digital signature. If one is found, it is
  151.  * verified and, if successful, the file is opened read-only
  152.  * (Note that signing a file causes it to be "locked" against
  153.  * writes.) If there is no signature, it is opened normally.
  154.  */
  155. void
  156. DemoEditDoc::OpenAndVerifyFile(
  157.         SFReply                        *macSFReply
  158.     )
  159. {
  160.         CSignedDataFile                *aSignedDataFile;
  161.         FSSpec                        macFSSpec;
  162.         short                        vRefNum;
  163.         long                        dirID;
  164.         long                        procID;
  165.         
  166.         aSignedDataFile = NULL;
  167.         if (gHasDigitalSignatureManager == FALSE) {
  168.             /*
  169.              * We shouldn't get here: the CApplication
  170.              * method should have disabled the "Open Signed
  171.              * File" menu option. If we do, just call our
  172.              * document open read-only method.
  173.              */
  174.             OpenFileReadOnly(macSFReply);
  175.         }
  176.         else {
  177.             /*
  178.              * FIrst, convert the SFReply to a FSSpec.
  179.              * This will crash on System 6 but we don't
  180.              * care as Digital Signatures require System 7.
  181.              */
  182.             FailOSErr(GetWDInfo(
  183.                 macSFReply->vRefNum,
  184.                 &vRefNum,
  185.                 &dirID,
  186.                 &procID
  187.             ));
  188.             FailOSErr(FSMakeFSSpec(
  189.                 vRefNum,
  190.                 dirID,
  191.                 macSFReply->fName,
  192.                 &macFSSpec
  193.             ));
  194.             /*
  195.              * Create a signature object. If the file is signed, try
  196.              * to verify it. If the file wasn't signed, open it normally.
  197.              * If it was signed, verify it and open it read-only
  198.              * if the verification succeeded.
  199.              */
  200.             aSignedDataFile = new (CSignedDataFile);
  201.             TRY {
  202.                 aSignedDataFile->ISignedDataFile();
  203.                 if (aSignedDataFile->FileIsSigned(&macFSSpec) == FALSE) {
  204.                     /*
  205.                      * File wasn't signed. Dispose of the signature
  206.                      * context and open the file using the normal
  207.                      * method.
  208.                      */
  209.                     aSignedDataFile->Dispose();
  210.                     OpenFile(macSFReply);
  211.                 }
  212.                 else {
  213.                     /*
  214.                      * The file is signed. Try to verify it. If
  215.                      * successful, we'll display the signer context
  216.                      * and open it read-only.
  217.                      */
  218.                     aSignedDataFile->VerifyFile(
  219.                             &macFSSpec,            /* File to verify        */
  220.                             gSIGStatusProc        /* Built-in status proc    */
  221.                         );
  222.                     aSignedDataFile->ShowSigner("\p");
  223.                     ForgetObject(aSignedDataFile);
  224.                     OpenFileReadOnly(macSFReply);
  225.                 }
  226.             }
  227.             CATCH {
  228.                 /*
  229.                  * Oops. Try to display a sensible error message for
  230.                  * some of the Digital Signature Manager failure states.
  231.                  * The text should, of course, be stored in resources.
  232.                  */
  233.                 InitCursor();
  234.                 switch (gLastError) {
  235.                 case userCanceledErr:
  236.                     Message("\pUser cancelled verification");
  237.                     goto exit;
  238.                 case kSIGSignerErr:
  239.                     Message("\pThe signature is not valid");
  240.                     goto exit;
  241.                 case kSIGVerifyFailedErr:
  242.                     Message("\pVerification failed");
  243. exit:                ForgetObject(aSignedDataFile);
  244.                     HiliteMenu(NOTHING);
  245.                     gApplication->JumpToEventLoop();
  246.                     break;
  247.                 case kSIGInvalidCredentialErr:
  248.                     /*
  249.                      * Umm, I haven't actually been able to
  250.                      * get this message, so the code might
  251.                      * be slightly inefficient here.
  252.                      */
  253.                     Message(
  254.                         "\pVerification succeeded, but credentials"
  255.                         " are invalid, pending, or expired."
  256.                     );
  257.                     aSignedDataFile->ShowSigner("\p");
  258.                     ForgetObject(aSignedDataFile);
  259.                     OpenFileReadOnly(macSFReply);
  260.                     NO_PROPAGATE;
  261.                 default:
  262.                     /*
  263.                      * Something is seriously wrong, use the
  264.                      * default error message method.
  265.                      */
  266.                     ForgetObject(aSignedDataFile);
  267.                     break;
  268.                 }
  269.             }
  270.             ENDTRY;
  271.         }
  272. }
  273.  
  274. /*
  275.  * CloseAndSignFile
  276.  * This is an alternative to the normal Close(FALSE)
  277.  * method. It closes the file (which will create/save it if
  278.  * necessary), then signs the object.
  279.  */
  280. void
  281. DemoEditDoc::CloseAndSignFile(void)
  282. {
  283.         CSignedDataFile                *aSignedDataFile;
  284.         FInfo                        fileInfo;
  285.         FSSpec                        macFSSpec;
  286.         
  287.         if (DoSave()) {
  288.             if (gHasDigitalSignatureManager == FALSE) {
  289.                 /*
  290.                  * This shouldn't happen (see note in OpenAndVerifyFile
  291.                  * above). If we get here however, just do a normal Close.
  292.                  */
  293.                 this->Close(FALSE);
  294.             }
  295.             else {
  296.                 /*
  297.                  * Because of the way the Close method operates, we
  298.                  * have to grab the file specification before closing
  299.                  * the file.
  300.                  */
  301.                 TRY {
  302.                     itsFile->GetFSSpec(&macFSSpec);
  303.                     if (this->Close(FALSE)) {
  304.                         /*
  305.                          * The file closed successfully (i.e., the user
  306.                          * didn't Cancel the close). Now, we can sign
  307.                          * the contents.
  308.                          */
  309.                         aSignedDataFile = new (CSignedDataFile);
  310.                         aSignedDataFile->ISignedDataFile();
  311.                         aSignedDataFile->SignFile(
  312.                             NULL,            /* No signer file given    */
  313.                             "\p",            /* Default prompt        */
  314.                             &macFSSpec,        /* FileSpec to sign        */
  315.                             gSIGStatusProc    /* Built-in status proc    */
  316.                         );
  317.                     }
  318.                 }
  319.                 CATCH {
  320.                     /*
  321.                      * Signing was unsuccessful. Display an
  322.                      * error message for some expected errors.
  323.                      * The text for these error messages should
  324.                      * be stored in resource strings, of course.
  325.                      */
  326.                     ForgetObject(aSignedDataFile);
  327.                     switch (gLastError) {
  328.                     case wrPermErr:
  329.                         Message(
  330.                             "\pCan't write to a read-only file:"
  331.                             " please save the file under a different name"
  332.                         );
  333.                         gApplication->JumpToEventLoop();
  334.                         break;
  335.                     case userCanceledErr:
  336.                         Message(
  337.                             "\pUser cancelled signature."
  338.                             " File is saved and closed."
  339.                         );
  340.                         NO_PROPAGATE;
  341.                         break;
  342.                     case kSIGPasswordErr:
  343.                         Message(
  344.                             "\pUser entered an incorrect password."
  345.                             " File is saved and closed."
  346.                         );
  347.                         NO_PROPAGATE;
  348.                         break;
  349.                     case kSIGSignerErr:
  350.                         Message("\pSigner error."
  351.                             " File is saved and closed."
  352.                         );
  353.                         NO_PROPAGATE;
  354.                         break;
  355.                     case kSIGSignerNotValidErr:
  356.                         Message(
  357.                             "\pInvalid signer."
  358.                             " File is saved and closed."
  359.                         );
  360.                         NO_PROPAGATE;
  361.                         break;
  362.                     default:
  363.                         break;
  364.                     }
  365.                 }
  366.                 ENDTRY;
  367.             }
  368.         }
  369. }
  370.  
  371. /*
  372.  * OpenFileReadOnly
  373.  * This is used by DemoEditDoc to open a file
  374.  * without write permission. It is a cut/paste revision of
  375.  * CEditDoc::OpenFile().
  376.  */
  377. void
  378. DemoEditDoc::OpenFileReadOnly(
  379.         SFReply                        *macSFReply
  380.     )
  381. {
  382.     CDataFile    *theFile;
  383.     Handle        theData;
  384.     Str63        theName;
  385.     OSErr        theError;
  386.  
  387.         /**
  388.          ** Create a file and send it a SFSpecify()
  389.          **    message to set up the name, volume, and
  390.          **    directory.
  391.          **
  392.          **/
  393.  
  394.     theFile = new(CDataFile);
  395.  
  396.         /**
  397.          **    Be sure to set the instance variable
  398.          **    so other methods can use the file if they
  399.          **    need to. This is especially important if
  400.          **    you leave the file open in this method.
  401.          **    If you close the file after reading it, you
  402.          **    should be sure to set itsFile to NULL.
  403.          **
  404.          **/
  405.  
  406.     itsFile = theFile;
  407.  
  408.     theFile->IDataFile();
  409.     theFile->SFSpecify(macSFReply);
  410.     
  411.  
  412.         /**
  413.          **    Send the file an Open() message to
  414.          **    open it. You can use the ReadSome() or
  415.          **    ReadAll() methods to get the contents of the file.
  416.          **
  417.          **/
  418.     theFile->Open(/* fsRdWrPerm */ fsRdPerm);
  419.     if (theFile->GetLength() > 10240L)
  420.     {
  421.         ParamText( "\pCan't open a file this big.", "\p", "\p", "\p");
  422.         PositionDialog('ALRT', 128);
  423.         InitCursor();
  424.         Alert(128, NULL);
  425.         
  426.         Dispose();
  427.         return;
  428.     }
  429.     
  430.  
  431.     theData = theFile->ReadAll();     /* ReadAll() creates the handle */
  432.  
  433.     BuildWindow(theData);
  434.  
  435.         /**
  436.          **    In your application, you'll probably store
  437.          **    the data in some form as an instance variable
  438.          **    in your document class. For this example, there's
  439.          **    no need to save it, so we'll get rid of it.
  440.          **
  441.          **/
  442.  
  443.     DisposHandle(theData);
  444.     itsFile->GetName(theName);
  445.     itsWindow->SetTitle(theName);
  446.     itsWindow->Select();            /* Don't forget to make the window active */
  447.     /*
  448.      * Since we opened the file read-only, we don't want
  449.      * to let the user try to write into the file. The
  450.      * simplest way to prevent this is to dispose of
  451.      * the file object.
  452.      */
  453.     ForgetObject(itsFile);
  454. }
  455.  
  456.  
  457.